#!/usr/bin/env ruby
#
# Created by Jerry Luk on 2008-05-01
# Copyright (c) 2008. All rights reserved.

# Represents the Google Calendar Data

module RSS
  GCAL_PREFIX = 'gcal'
  GCAL_URI = 'http://schemas.google.com/gCal/2005'
  
  module BaseGCalModel
    def append_features(klass)
      super
      base_append_features(klass, GCalModel::ELEMENT_NAME_INFOS, GCAL_PREFIX, GCAL_URI)      
    end
  end
  
  module GCalModel
    extend BaseModel
    extend BaseGCalModel
    
    TEXT_ELEMENTS = {
      "timezone" => nil,
      "hidden" => nil,
      "color" => nil,
      "accesslevel" => nil,
      "selected" => nil,
      "uid" => nil,
      "sequence" => nil,
      "quickadd" => nil,
      "webContent" => nil
    }
    
    ATTRIBUTES = GDataModel::ATTRIBUTES + [["url", "", false],
                                           ["width", "", false],
                                           ["height", "", false]]
    
    ELEMENT_NAME_INFOS = GCalModel::TEXT_ELEMENTS.to_a
    ELEMENTS = TEXT_ELEMENTS.keys
    
    ELEMENTS.each do |name, plural_name|
      create_class(name, plural_name, GCAL_PREFIX, GCAL_URI)
    end
  end
    
  GCalModel::ELEMENTS.each do |name|
    class_name = Utils.to_class_name_with_prefix(name, GCAL_PREFIX)
    BaseListener.install_class_name(GCAL_URI, name, class_name)
  end
  
  GCalModel::ELEMENTS.collect! { |name| "#{GCAL_PREFIX}_#{name}"}
end

module RSS
  module Atom
    Feed.install_ns(GCAL_PREFIX, GCAL_URI)
    class Feed
      include GCalModel
      class Entry; include GCalModel; end
    end

    class Entry
      include GCalModel
    end
  end
end

module Google
  class GCalendarsFeed < GData
    attr_accessor :calendars
    
    def initialize(data=RSS::Atom::Feed.new)
      super(data)
    end
    
    def calendars
      @calendars ||= @atom.entries.map { |e| GCalendar.new(e) } if @atom
    end
  end
  
  class GCalendar < GData
    attr_accessor :events
    
    def events
      @events ||= @atom.entries.map { |e| GEvent.new(e) } if @atom
    end
    
    def link
      @atom.link.href
    end
    
    def selected 
      @atom.gcal_selected = RSS::GCalModel::GcalSelected.new unless @atom.gcal_selected
      @atom.gcal_selected.value
    end
    
    def selected=(s)
      @atom.gcal_selected = RSS::GCalModel::GcalSelected.new unless @atom.gcal_selected
      @atom.gcal_selected.value = s
    end
  end
  
  class GEvent < GData  
    attr_accessor :guests
      
    STATUS = {
      :canceled  => 'http://schemas.google.com/g/2005#event.canceled',
      :confirmed => 'http://schemas.google.com/g/2005#event.confirmed',
      :tentative => 'http://schemas.google.com/g/2005#event.tentative'     
    }
    
    VISIBILITY = {
      :confidential => 'http://schemas.google.com/g/2005#event.confidential',
      :default => 'http://schemas.google.com/g/2005#event.default',
      :private => 'http://schemas.google.com/g/2005#event.private',
      :public => 'http://schemas.google.com/g/2005#event.public'
    }
    
    TRANSPARENCY = {
      :opaque => 'http://schemas.google.com/g/2005#event.opaque',
      :transparent => 'http://schemas.google.com/g/2005#event.transparent'
    }
    
    def guests
      @guests ||= @atom.gd_whos.map { |w| GPerson.new(w) } if @atom
    end
    
    def link
      self.atom_id
    end
    
    def visibility
      @atom.gd_visibility.value
    end
    
    def visibility=(a_visibility)
      @atom.gd_visibility.value = a_visibility
    end
    
    def status
      @atom.gd_event_status.value
    end
    
    def status=(a_status)
      @atom.gd_event_status.value = a_status
    end
    
    def transparency
      @atom.gd_transparency.value
    end
    
    def transparency=(a_transparency)
      @atom.gd_transparency.value = a_transparency
    end
    
    def description
      @atom.content.content if @atom.content
    end
    
    def description=(a_description)
      @atom.content = RSS::Atom::Feed::Entry::Content.new unless @atom.content
      @atom.content.content = a_description
    end
    
    def where
      @atom.gd_where.valueString
    end
    
    def where=(a_place)
      @atom.gd_where = RSS::GDataModelWithGCalExtension::GdWhere.new("") unless @atom.gd_where
      @atom.gd_where.valueString = a_place
    end
    
    def recurrence
      @atom.gd_recurrence.content if @atom.gd_recurrence
    end
    
    def recurrence=(a_recurrence)
      @atom.gd_recurrence = RSS::GDataModelWithGCalExtension::GdRecurrence.new("") unless @atom.gd_recurrence
      @atom.gd_recurrence.content = a_recurrence
    end
    
    def start_time
      @atom.gd_when.start_time if @atom.gd_when
    end
    
    def start_time=(a_start_time)
      @atom.gd_when = RSS::GDataModelWithGCalExtension::GdWhen.new unless @atom.gd_when
      @atom.gd_when.start_time = a_start_time.w3cdtf
    end
    
    def end_time
      @atom.gd_when.end_time if @atom.gd_when
    end
    
    def end_time=(a_end_time)
      @atom.gd_when = RSS::GDataModelWithGCalExtension::GdWhen.new unless @atom.gd_when
      @atom.gd_when.end_time = a_end_time.w3cdtf
    end
    
    def uid
      @atom.gcal_uid.value
    end
    
    def original_id
      @atom.gd_original_event ? @atom.gd_original_event.id : nil
    end
    
    def original_start_time
      @atom.gd_original_event && @atom.gd_original_event.gd_when ? 
      @atom.gd_original_event.gd_when.start_time : nil
    end
    
  end
  
  class GPerson < GData
    RELATIONSHIP = {      
      :attendee   => 'http://schemas.google.com/g/2005#event.attendee',
      :organizer  => 'http://schemas.google.com/g/2005#event.organizer', 
      :performer  => 'http://schemas.google.com/g/2005#event.performer',
      :speaker    => 'http://schemas.google.com/g/2005#event.speaker',
      :bcc        => 'http://schemas.google.com/g/2005#message.bcc', 
      :cc         => 'http://schemas.google.com/g/2005#message.cc',   
      :from       => 'http://schemas.google.com/g/2005#message.from',
      :reply_to   => 'http://schemas.google.com/g/2005#message.reply-to',
      :to         => 'http://schemas.google.com/g/2005#message.to'
    }
    
    ATTENDEE_TYPE = {
      :optional => 'http://schemas.google.com/g/2005#event.optional',
      :required =>'http://schemas.google.com/g/2005#event.required'
    }
    
    ATTENDEE_STATUS = {
      :accepted   => 'http://schemas.google.com/g/2005#event.accepted',
      :declined   => 'http://schemas.google.com/g/2005#event.declined',
      :invited    => 'http://schemas.google.com/g/2005#event.invited',
      :tentative  =>'http://schemas.google.com/g/2005#event.tentative'
    }
    
    def initialize(data=RSS::GDataModelWithGCalExtension::GdWho)
      super(data)
    end
    
    def relationship
      @atom.rel
    end
    
    def relationship=(a_relationship)
      @atom.rel = a_relationship
    end
    
    def name
      @atom.valueString
    end
    
    def name=(a_name)
      @atom.valueString = a_name
    end
  end
  
  # Do not use GData here because it will convert into an Event by Google
  # once submitted to Google
  class GCalGadget
    attr_accessor :icon_url, :title, :gadget_type, :gadget_url, :width, :height, :date
    def initialize(options={})
      self.icon_url = options[:icon_url]
      self.title = options[:title]
      self.gadget_type = options[:gadget_type] # text/html, application/x-google-gadgets+xml
      self.gadget_url = options[:gadget_url]
      self.width = options[:width]
      self.height = options[:height]
      self.date = options[:date] if options[:date]
    end
    
    def date=(date)
      @date = date.to_date
    end
    
    def to_xml
      xml = <<EOF
<entry xmlns="http://www.w3.org/2005/Atom" 
       xmlns:gCal="http://schemas.google.com/gCal/2005"
       xmlns:gd="http://schemas.google.com/g/2005" >
  <title>#{@title}</title>
  <link rel="http://schemas.google.com/gCal/2005/webContent" 
        href="#{@icon_url}" 
        title="#{@title}" 
        type="#{@gadget_type}">
    <gCal:webContent url="#{@gadget_url}" width="#{@width}" height="#{@height}">
    </gCal:webContent>
  </link>
  <gd:when startTime="#{@date.to_s}" />
</entry>
EOF
    end
  end
end